9.3 EdeficePinGenerator PIN generation algorithm

The EdeficePinGenerator PIN generation algorithm uses the card serial number as diversification data. The PIN generation key is used to generate the PIN. If you have the card serial number, the same key that is used within MyID, and the details of the following algorithm, you can generate the same PINs as MyID.

Alternatively, you can use the user's logon name as the diversification data; this ensures that the user has the same PIN for all of their cards. To use the logon name, set the Use logon name for server PIN generation option on the PINs page of the Security Settings workflow.

9.3.1 Generating the PIN

The process for generating the PIN is as follows:

  1. Use the card serial number as the input to a SHA1 hash.

    This generates a 20-byte hash value.

  2. Truncate the 20-byte hash to the first 16 bytes. Encryption is carried out on 8-byte blocks, so we want to carry out the encryption on two blocks without padding.
  3. Encrypt the hash with the PIN generation key.

    • Use 3DES encryption in cipher block chaining mode. This generates a 16-byte hex value.
    • You do not want any header information in the encrypted data.
    • For the initialization vector, use 8 bytes of 0x00.
    • Do not use any padding.
  4. For each byte, divide by the alphabet size (numeric, alpha or alphanumeric) and take the remainder; in other words, <byte> modulo <alphabet size>.

    As there are 16 bytes, you can generate PINs up to 16 characters long. If the PIN is 6 characters long, for example, perform this operation on the first 6 bytes in the encrypted data.

  5. Use this value as a look-up in the alphabet table – see section 9.3.2, Alphabet tables.

    For example, if the byte is 2C, and the alphabet size is 10 (for numeric PINs):

    2C = 44 decimal

    44 modulo 10 = 4

    Entry 4 in the numeric table = '4'

9.3.2 Alphabet tables

9.3.2.1 Numeric

The numeric alphabet has size 10, and the following entries:

Index

0

1

2

3

4

5

6

7

8

9

Value

0 1 2 3 4 5 6 7 8 9

For example, a lookup of 0 returns 0, and a lookup of 7 returns 7.

Note: The EdeficePinGenerator PIN generator uses a numeric alphabet only. If you want to generate PINs that use alphabetic or symbol characters, you are recommended to use the EdeficePolicyPinGenerator PIN generator instead; see section 9.4, EdeficePolicyPinGenerator PIN generation algorithm.

9.3.2.2 Alpha

The alpha alphabet has size 52, and has the following entries:

Index

0

1

2

3

4

5

6

7

8

9

Value

a b c d e f g h i j

Index

10

11

12

13

14

15

16

17

18

19

Value

k l m n o p q r s t

Index

20

21

22

23

24

25

26

27

28

29

Value

u v w x y z A B C D

Index

30

31

32

33

34

35

36

37

38

39

Value

E F G H I J K L M N

Index

40

41

42

43

44

45

46

47

48

49

Value

O P Q R S T U V W X

Index

50

51

 

 

 

 

 

 

 

 

Value

Y Z

 

 

 

 

 

 

 

 

For example, a lookup of 0 returns a, and a lookup of 37 returns L.

9.3.2.3 Alphanumeric

The alphanumeric alphabet has size 62, and has the following entries:

Index

0

1

2

3

4

5

6

7

8

9

Value

0 1 2 3 4 5 6 7 8 9

Index

10

11

12

13

14

15

16

17

18

19

Value

a b c d e f g h i j

Index

20

21

22

23

24

25

26

27

28

29

Value

k l m n o p q r s t

Index

30

31

32

33

34

35

36

37

38

39

Value

u v w x y z A B C D

Index

40

41

42

43

44

45

46

47

48

49

Value

E F G H I J K L M N

Index

50

51

52

53

54

55

56

57

58

59

Value

O P Q R S T U V W X

Index

60

61

 

 

 

 

 

 

 

 

Value

Y Z

 

 

 

 

 

 

 

 

For example, a lookup of 0 returns 0, and a lookup of 37 returns B.

9.3.3 Example

If a numeric pin with a length of 6 characters is requested for a card with serial number 0000000002000304 the process is as follows:

  1. The card serial number, 0000000002000304, is hashed using SHA1 to produce:

    A1CB37418AF6ADB8A18E0673A2198E683D4992D6

  2. This is then shortened to 16 bytes, as we want to encode two whole 8-byte blocks:

    A1CB37418AF6ADB8A18E0673A2198E68

  3. This hash is then 3DES CBC mode encrypted using a shared key to produce, for example:

    7849DE09B259DE772EC0DCFE269E9A40

  4. Each byte is used to look up into the numeric alphabet array (size 10). For a 6 character numeric pin this results in:

    78 (hex) = 120 (dec) mod 10 = 0

    49 (hex) = 73  (dec) mod 10 = 3

    DE (hex) = 222 (dec) mod 10 = 2

    09 (hex) = 9   (dec) mod 10 = 9

    B2 (hex) = 178 (dec) mod 10 = 8

    59 (hex) = 89  (dec) mod 10 = 9

  5. The PIN returned is 032989.

9.3.3.1 C# example

The following is sample code that generates PINs using C#.

Copy
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace PINGeneration
{
class Program
{
static void Main(string[] args)
{
// Alphabet and PIN size
char[] alphabet = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
int alphabetsize = alphabet.Length;
int pinlength = 8;


// Encryption key
byte[] key = { 0x31, 0x28, 0x7A, 0x5A, 0x36, 0x26, 0x35, 0x31, 0x32, 0x71, 0x71, 0x53, 0x3D, 0x2F, 0x33, 0xA7, 0x21, 0x4C, 0x3F, 0x61, 0x44, 0x31, 0x55, 0x38 }; 
//Data to be encoded - device serial number
string data = "1034";
//Convert to a byte array
Encoding ascii = Encoding.ASCII;
byte[] databytes = ascii.GetBytes(data);

    // Create SHA1 hash of data
SHA1 shaM = new SHA1Managed();
byte[] hash = SHA1Managed.Create().ComputeHash(Encoding.Default.GetBytes(data));
byte[] hash16 = new byte[16];

    // Copy the first 16 bytes of the hash array
Array.Copy(hash,hash16,16);
 
// Set the initialisation vector to 8 bytes of 0x0
byte[] iv = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; 
 
string ciphertext = "";
string pin = "";
string hashhex = "";
string hashhex16 = "";

    // Set encryption options.
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.KeySize = 192;
des.Key = key;
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.None;
des.IV = iv;

    // Encrypt hashed data
ICryptoTransform ic = des.CreateEncryptor();
byte[] enc = ic.TransformFinalBlock(hash, 0, 16);
for (int i = 0; i < enc.Length; i++)
{
ciphertext = ciphertext + enc[i].ToString("X2");


    // Generate PIN from the ciphertext
for (int x = 0; x < pinlength; x++)
{
pin = pin + alphabet[Convert.ToInt32(ciphertext.Substring(x * 2, 2),16) % alphabetsize];
}
 
for (int i = 0; i < hash.Length; i++)
{
hashhex = hashhex + hash[i].ToString("X2");
}
for (int i = 0; i < hash16.Length; i++)
{
hashhex16 = hashhex16 + hash16[i].ToString("X2");
}

Console.WriteLine("Sample PIN generation algorithm output");
Console.WriteLine();
Console.WriteLine("Alphabet size:       " + alphabetsize);
Console.WriteLine("Required PIN length: " + pinlength);
Console.WriteLine("Data:                " + data);
Console.WriteLine("SHA1 hash of data:   " + hashhex);
Console.WriteLine("16 bytes of hash:    " + hashhex16);
Console.WriteLine("Encrypted:           " + ciphertext);
Console.WriteLine("\nPIN:                 " + pin);
Console.WriteLine("\nPress any key to continue…");
Console.ReadKey(true);
}
}
}